package com.springbootx.mybatis.config.transactional;

import com.springbootx.mybatis.config.DataSourceRouting;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Tony.niu (hystrix0779@yeah.net)
 * @version V1.0
 * @date 2020/6/30
 **/
@Aspect
@Order(2)
@Component
public class TransactionAop {
    private final Logger log = LoggerFactory.getLogger(getClass());
    @Resource
    BeanFactory beanFactory;

    @Pointcut("@annotation(com.springbootx.mybatis.config.transactional.MoreTransaction)")
    public void moreTransaction() {
    }

    @Around("moreTransaction()&&@annotation(annotation)")
    public Object aroundTransaction(ProceedingJoinPoint point, MoreTransaction annotation) throws Throwable {
        IsolationLevel isolationLevel = annotation.isolationLevel();
        DataSourceRouting dataSourceRouting=ApplicationContextUtil.getBean(DataSourceRouting.class);
        Copy threadCopy = dataSourceRouting.getCopy();
        String className = point.getTarget().getClass().getName();
        String methodName =  point.getSignature().getName();
        String currentMethod=className+"."+methodName;
        if (Objects.isNull(threadCopy)){
            threadCopy=Copy.builder().
                    currentMethod(currentMethod).
                    mainMethod(currentMethod).
                    tranSwitch(Boolean.TRUE).
                    isolationLevel(isolationLevel).
                    connection(new ConcurrentHashMap<>()).
                    resolvedDataSources(dataSourceRouting.getResolvedDataSources()).
                    build();
            dataSourceRouting.setCopy(threadCopy);
        }else {
            threadCopy.setCurrentMethod(currentMethod);
        }
        Object proceed;
        try {
            proceed = point.proceed();
        } catch(Exception ex){
            if (currentMethod.equals(threadCopy.getMainMethod())) {
                dataSourceRouting.rollback();
                log.info("事务回滚");
            }
            throw ex;
        }
        if (currentMethod.equals(point.getTarget().getClass().getName()+"."+point.getSignature().getName())) {
            dataSourceRouting.doCommit();
        }
        return proceed;

    }
}